﻿using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Unity.Entities;
using TMPro;
using System;

public class SingleGameCenter : MonoBehaviour {
    private static SingleGameCenter _instance;
    public static SingleGameCenter Instance => _instance;

    [SerializeField] TextMeshPro tmpScore;

    int curScore;
    readonly int[] SCORE_LIST = { 100, 300, 600, 1000 };
    readonly int[] TIME_REWARD_LIST = { 40, 30, 20, 10 };
    readonly float[] TIME_CRITERION_LIST = { 1f, 2f, 3f, 4f };

    Entity gameEntity;

    private void Awake() {
        _instance = this;
    }

    private void Start() {
        // 积分处理关联
        var world = World.DefaultGameObjectInjectionWorld;
        if (null == world) {
            World.DefaultGameObjectInjectionWorld = new World("SingleGame");
            world = World.DefaultGameObjectInjectionWorld;
            world.GetOrCreateSystem<MinoSpawnerSystem>();
        }
        world.GetOrCreateSystem<EliminationSystem>().OnEliminated += OnEliminated;
        world.GetOrCreateSystem<MinoMovementSystem>().OnFallDown += OnFallDown;
        world.GetOrCreateSystem<GameOverSystem>().OnGameOver += OnGameOver;
        // world.GetOrCreateSystem<MinoMovementSystem>().OnGameOver += OnGameOver;
        curScore = 0;
        tmpScore.text = curScore.ToString();

        var entityManager = world.EntityManager;
        gameEntity = entityManager.CreateEntity();
        world.GetOrCreateSystem<MinoInstructionSystem>().gameEntity = gameEntity;
        world.GetOrCreateSystem<MinoSpawnerSystem>().gameEntity = gameEntity;
        world.GetOrCreateSystem<MinoMovementSystem>().gameEntity = gameEntity;
        world.GetOrCreateSystem<EliminationSystem>().gameEntity = gameEntity;

        // 添加自动坠落计时器 & 指令队列
        entityManager.AddComponentData(gameEntity, new AutoMoveTimeStamp { Value = 0 });
        entityManager.AddComponentData(gameEntity, new MinoBornTime { Value = 0 });
        entityManager.AddBuffer<MinoInstraction>(gameEntity);

        // 填充边界
        var dBuffer = entityManager.AddBuffer<MinoGridState>(gameEntity);
        for (int i = 0, iCount = 21; i < iCount; i++) {
            for (int j = 0, jCount = 12; j < jCount; j++) {
                int v = 0;
                if (i == 0 || j == 0 || j + 1 == jCount) {
                    v = 1;
                }
                dBuffer.Add(new MinoGridState { Value = v });
            }
        }
		// 开始生成形状
		entityManager.AddComponentData(gameEntity, new MinoGridEvent { Value = MinoGridEventType.CreateTetromino }); 
    }
    // 结束游戏时，System 可能已经被释放了
    // 但对于切换场景时，可能还是需要进行处理
    // public void OnDestroy() {
    //     var world = World.DefaultGameObjectInjectionWorld;
    //     world.GetOrCreateSystem<EliminationSystem>().OnEliminated -= OnEliminated;
    //     world.GetOrCreateSystem<MinoMovementSystem>().OnFallDown -= OnFallDown;
    //     world.GetOrCreateSystem<MinoMovementSystem>().OnGameOver -= OnGameOver;
    // }

    public void Retry() {
        // 1.清除所有的 Static
        // 2.重置 MinoSpawnSystem
        // 3.重置 MinoGridBuffer
        // 4.设置 MinoGridState 为 CreateTetromino
        var entityManager = World.DefaultGameObjectInjectionWorld.EntityManager;
        var allEntities = entityManager.GetAllEntities();
        foreach (var entity in allEntities) {
            if (entityManager.HasComponent<MinoTag>(entity)
                && !entityManager.HasComponent<Prefab>(entity)) { 
                entityManager.DestroyEntity(entity);
            }
        } 
        // 重置 MinoSpawnSystem
        World.DefaultGameObjectInjectionWorld.GetExistingSystem<MinoSpawnerSystem>().Retry();
        // 重置 MinoGridState
        var dBuffer = entityManager.GetBuffer<MinoGridState>(gameEntity);
        for (int i = 0, iCount = 21; i < iCount; i++) {
            for (int j = 0, jCount = 12; j < jCount; j++) {
                int v = 0;
                if (i == 0 || j == 0 || j + 1 == jCount) {
                    v = 1;
                }
                int idx = i * jCount + j;
                var state = dBuffer[idx];
                state.Value = v;
                dBuffer[idx] = state;
            }
        }
        // 开始创建形状
        entityManager.SetComponentData(gameEntity, new MinoGridEvent { Value = MinoGridEventType.CreateTetromino });
    }
    public void BackToStartMenu() {
        var entityManager = World.DefaultGameObjectInjectionWorld.EntityManager;
        entityManager.DestroyEntity(entityManager.UniversalQuery);

        MySceneManager.Instance.SwitchToStartMenuScene();
    }

    private void OnEliminated(object sender_, int count_) {
        curScore += SCORE_LIST[count_ - 1];
        tmpScore.text = curScore.ToString();
    }
    private void OnFallDown(object sender_, float elapse_) {
        for (int i = 0, iCount = TIME_CRITERION_LIST.Length; i < iCount; i++) {
            if (elapse_ < TIME_CRITERION_LIST[i]) {
                curScore += TIME_REWARD_LIST[i];
                tmpScore.text = curScore.ToString();
                break;
            }
        }
    }
    private void OnGameOver(object sender_, System.EventArgs eventArgs_) {
        // 显示游戏结束界面
        WindowManager.Instance.ShowGameOverPanel(curScore);
    }

    #region ButtonEvents
    public void OnLeftBtnClicked() {
        World.DefaultGameObjectInjectionWorld.EntityManager.GetBuffer<MinoInstraction>(gameEntity).Add(new MinoInstraction { Value = InstractionType.Left });
    }
    public void OnRightBtnClicked() {
        World.DefaultGameObjectInjectionWorld.EntityManager.GetBuffer<MinoInstraction>(gameEntity).Add(new MinoInstraction { Value = InstractionType.Right });
    }
    public void OnRotateBtnClicked() {
        World.DefaultGameObjectInjectionWorld.EntityManager.GetBuffer<MinoInstraction>(gameEntity).Add(new MinoInstraction { Value = InstractionType.Rotate });
    }
    public void OnDownBtnClicked() {
        World.DefaultGameObjectInjectionWorld.EntityManager.GetBuffer<MinoInstraction>(gameEntity).Add(new MinoInstraction { Value = InstractionType.Down });
    }
    public void OnFallBtnClicked() {
        World.DefaultGameObjectInjectionWorld.EntityManager.GetBuffer<MinoInstraction>(gameEntity).Add(new MinoInstraction { Value = InstractionType.Fall });
     }
    #endregion
}
